﻿using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using WebApiCore.Reflection;
using WebApiCore.Setting;

namespace WebApiCore
{
    public static class App
    {
        /// <summary>
        /// 全局配置文件
        /// </summary>
        public static OptionsSetting OptionsSetting => CatchOrDefault(() => ServiceProvider?.GetService<IOptions<OptionsSetting>>()?.Value);

        /// <summary>
        /// 服务提供器
        /// </summary>
        public static IServiceProvider ServiceProvider => InternalApp.ServiceProvider;

        /// <summary>
        /// 获取请求上下文
        /// </summary>
        public static HttpContext HttpContext => CatchOrDefault(() => ServiceProvider?.GetService<IHttpContextAccessor>()?.HttpContext);

        /// <summary>
        /// 获取请求上下文用户
        /// </summary>
        public static ClaimsPrincipal User => HttpContext?.User;

        /// <summary>
        /// 获取用户名
        /// </summary>
        public static string UserName => User?.Identity?.Name;

        /// <summary>
        /// 获取Web主机环境
        /// </summary>
        public static IWebHostEnvironment WebHostEnvironment => InternalApp.WebHostEnvironment;
        /// <summary>
        /// 获取全局配置
        /// </summary>
        public static IConfiguration Configuration => CatchOrDefault(() => InternalApp.Configuration, new ConfigurationBuilder().Build());

        /// <summary>
        /// 获取请求生命周期的服务
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <returns></returns>
        public static TService GetService<TService>()
            where TService : class
        {
            return GetService(typeof(TService)) as TService;
        }

		/// <summary>
		/// 获取请求生存周期的服务
		/// </summary>
		/// <typeparam name="TService"></typeparam>
		/// <param name="serviceProvider"></param>
		/// <returns></returns>
		public static TService GetService<TService>(IServiceProvider serviceProvider = default)
			where TService : class
		{
			return GetService(typeof(TService), serviceProvider) as TService;
		}

		/// <summary>
		/// 获取请求生存周期的服务
		/// </summary>
		/// <param name="type"></param>
		/// <param name="serviceProvider"></param>
		/// <returns></returns>
		public static object GetService(Type type, IServiceProvider serviceProvider = default)
		{
			return (serviceProvider ?? ServiceProvider).GetService(type);
		}

		/// <summary>
		/// 获取请求生命周期的服务
		/// </summary>
		/// <param name="type"></param>
		/// <returns></returns>
		public static object GetService(Type type)
        {
            return ServiceProvider.GetService(type);
        }

        /// <summary>
        /// 获取请求生命周期的服务
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <returns></returns>
        public static TService GetRequiredService<TService>()
            where TService : class
        {
            return GetRequiredService(typeof(TService)) as TService;
        }

        /// <summary>
        /// 获取请求生命周期的服务
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object GetRequiredService(Type type)
        {
            return ServiceProvider.GetRequiredService(type);
        }

        /// <summary>
        /// 处理获取对象异常问题
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="action">获取对象委托</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns>T</returns>
        private static T CatchOrDefault<T>(Func<T> action, T defaultValue = null)
            where T : class
        {
            try
            {
                return action();
            }
            catch
            {
                return defaultValue ?? null;
            }
        }

		/// <summary>
		/// 获取选项
		/// </summary>
		/// <typeparam name="TOptions">强类型选项类</typeparam>
		/// <param name="serviceProvider"></param>
		/// <returns>TOptions</returns>
		public static TOptions GetOptions<TOptions>(IServiceProvider serviceProvider = default)
			where TOptions : class, new()
		{
			return CatchOrDefault(() => GetService<IOptions<TOptions>>(serviceProvider ?? ServiceProvider).Value);
		}

		/// <summary>
		/// 获取应用有效程序集
		/// </summary>
		/// <returns>IEnumerable</returns>
		private static (IEnumerable<Assembly> Assemblies, IEnumerable<Assembly> ExternalAssemblies) GetAssemblies()
		{
			// 需排除的程序集后缀
			var excludeAssemblyNames = new string[] {
				"Database.Migrations"
			};

			// 读取应用配置
			var supportPackageNamePrefixs = Array.Empty<string>();

			IEnumerable<Assembly> scanAssemblies;

			// 获取入口程序集
			var entryAssembly = Assembly.GetEntryAssembly();

			var dependencyContext = DependencyContext.Default;

			// 读取项目程序集或 Furion 官方发布的包，或手动添加引用的dll，或配置特定的包前缀
			scanAssemblies = dependencyContext.RuntimeLibraries
			   .Where(u =>
					  (u.Type == "project" && !excludeAssemblyNames.Any(j => u.Name.EndsWith(j)))   // 当前项目
				)    
			   .Select(u => Reflect.GetAssembly(u.Name));

			IEnumerable<Assembly> externalAssemblies = Array.Empty<Assembly>();

			//// 加载 `appsetting.json` 配置的外部程序集
			//if (Settings.ExternalAssemblies != null && Settings.ExternalAssemblies.Any())
			//{
			//	foreach (var externalAssembly in Settings.ExternalAssemblies)
			//	{
			//		// 加载外部程序集
			//		var assemblyFileFullPath = Path.Combine(AppContext.BaseDirectory
			//			, externalAssembly.EndsWith(".dll") ? externalAssembly : $"{externalAssembly}.dll");

			//		// 根据路径加载程序集
			//		var loadedAssembly = Reflect.LoadAssembly(assemblyFileFullPath);
			//		if (loadedAssembly == default) continue;
			//		var assembly = new[] { loadedAssembly };

			//		// 合并程序集
			//		scanAssemblies = scanAssemblies.Concat(assembly);
			//		externalAssemblies = externalAssemblies.Concat(assembly);
			//	}
			//}

			//// 处理排除的程序集
			//if (Settings.ExcludeAssemblies != null && Settings.ExcludeAssemblies.Any())
			//{
			//	scanAssemblies = scanAssemblies.Where(ass => !Settings.ExcludeAssemblies.Contains(ass.GetName().Name, StringComparer.OrdinalIgnoreCase));
			//}

			return (scanAssemblies, externalAssemblies);
		}

		/// <summary>
		/// 加载程序集中的所有类型
		/// </summary>
		/// <param name="ass"></param>
		/// <returns></returns>
		private static IEnumerable<Type> GetTypes(Assembly ass)
		{
			var types = Array.Empty<Type>();

			try
			{
				types = ass.GetTypes();
			}
			catch
			{
				Console.WriteLine($"Error load `{ass.FullName}` assembly.");
			}

			return types.Where(u => u.IsPublic);
		}

		/// <summary>
		/// 应用有效程序集
		/// </summary>
		public static readonly IEnumerable<Assembly> Assemblies;

		/// <summary>
		/// 有效程序集类型
		/// </summary>
		public static readonly IEnumerable<Type> EffectiveTypes;

		/// <summary>
		/// 外部程序集
		/// </summary>
		internal static IEnumerable<Assembly> ExternalAssemblies;

		/// <summary>
		/// 构造函数
		/// </summary>
		static App()
		{
			// 加载程序集
			var assObject = GetAssemblies();
			Assemblies = assObject.Assemblies;
			ExternalAssemblies = assObject.ExternalAssemblies;

			// 获取有效的类型集合
			EffectiveTypes = Assemblies.SelectMany(GetTypes);
		}
	}
}
